package com.cf.main;

import java.io.BufferedReader;
import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.util.HashSet;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
import java.util.Scanner;
import java.util.Set;
import java.util.TreeSet;

/*
 * 基于信任和近邻评分填充的协同过滤推荐算法
 * 度量用户间相似性的方法选用：皮尔逊相似度
 * 输入：UserID  ， ItemID
 * 输出1：预测评分值
 * 输出2：RMSE（推荐质量）
 * 输出3：MAE（推荐质量）
 * */
public class TrustAndSimilarityBasedCF {

	public static final int USERSIZE = 943;
	public static final int ITEMSIZE = 1682;
	public static int UN = 20;// 某用户的最近邻居数

	public int[] itemNumOfUser = new int[USERSIZE + 1];// 每个用户为几部电影进行了评分
	public int[] userNumOfItem = new int[ITEMSIZE + 1];// 每个项目有多少用户进行了评分
	public double[] averageRateOfUser = new double[USERSIZE + 1];// 每个用户所有打分的平均分
	public double[] averageRateOfItem = new double[ITEMSIZE + 1];// 每个项目的所有用户评分的平均分
	public double[][] rate = new double[USERSIZE + 1][ITEMSIZE + 1];// 评分矩阵，根据训练集建立
	public double[][] DealedOfRate = new double[USERSIZE + 1][ITEMSIZE + 1];// 针对稀疏问题处理后的评分矩阵
	
	public double[] userValueArray = new double[USERSIZE + 1];// 用户价值度；
	public double[] userPowerArray = new double[USERSIZE + 1];// 用户权威度；
	public int[] S = new int[USERSIZE + 1]; // 用户评分偏差小于一定阈值的项目个数
	public int[][] D = new int[USERSIZE + 1][USERSIZE + 1]; // 集合
	public double[] Trust = new double[USERSIZE + 1];// 用户信任度；
	public double[][] trustArray = new double[USERSIZE + 1][USERSIZE + 1];// 用户相互信任度矩阵；
	public double[][] MTrust = new double[USERSIZE + 1][USERSIZE + 1];// 用户直接信任度矩阵
	public double[][] ITrust = new double[USERSIZE + 1][USERSIZE + 1];// 用户间接信任度矩阵
	public double[][] ZTrust = new double[USERSIZE + 1][USERSIZE + 1];// 用户综合信任度矩阵
	public double[][] STrust = new double[USERSIZE + 1][USERSIZE + 1];// 用户相似信任综合矩阵
	public double[][] similarityArray = new double[USERSIZE + 1][USERSIZE + 1];// 用户相似信任综合矩阵
	public String [][] commonNeighborArray= new String[USERSIZE + 1][USERSIZE + 1];
	
	Neighbor[][] NeighborArray = new Neighbor[USERSIZE + 1][UN + 1];// 每个用户的最近的UN个邻居

	List<Double> x = new LinkedList<Double>();// LinkedList按照对象加入的顺序存储
	List<Double> y = new LinkedList<Double>();
	
	@SuppressWarnings("resource")
	public static void main(String args[]) throws Exception {

		TrustAndSimilarityBasedCF cf = new TrustAndSimilarityBasedCF();
		//		Scanner sc = new Scanner(System.in);
		//		int n = 0;
		//		System.out.print("请输入近邻数量矩阵的长度：");
		//		n = sc.nextInt();
		//		System.out.println();
		//		neighborNum = new int[n];
		//		System.out.print("请依次输入近邻数量，以空格分开，回车结束输入");
		//		
		//		int i = 0;
		//		while(  i < n && sc.hasNext()) {
		//			neighborNum[i] = sc.nextInt();
		//			i++;
		//		}
		//		sc.close();
		//		System.out.println();
		//		for (int t : neighborNum) {
		//			neighborList.add(new Neighbor[UESRSIZE + 1][t + 1]);
		//		}
		
		
		Scanner sc = new Scanner(System.in);
		System.out.print("请输入近邻数量：");
		UN = sc.nextInt();
		sc.close();
		System.out.println();
		
		long startTime = System.currentTimeMillis();
		if (cf.readFile("/ml_data_0/u1.base")) {
			System.out.println("正在分析，请稍等！");
			System.out.println();
			
			// 用户评分均值数组计算，项目评分矩阵素组计算
			cf.getRateItemNumOfUser();
			cf.getAverageRateOfUser();
			cf.getRateUserNumOfItem();
			cf.getAverageRateOfItem();
			// 处理数据稀疏性问题
			cf.dealRate();
			
			// 计算相似性矩阵
			cf.calculateSimilarityArray(); 
			cf.calculateUserValueArray(0.0d , 1.0d);
			cf.calculateUserPowerArray(0.5d);
			cf.calculateD(0.5d);

			// 计算用户直接信任度
			cf.calculateMTrust(0.5);
			
			// 计算用户信任传递人矩阵
			cf.calculateCommonNeighborArray();
			
			// 计算用户间接信任度
			cf.calculateITrust(0.5);
			
			// 计算综合信任度
			cf.calculateZTrustArray();
			
			// 计算信任-相似综合矩阵
			cf.calculateSTrustArray();
			
			// 计算邻居矩阵
			cf.calculateNeighborArray();
			
			// 测试
			// 读取测试文件
			InputStream is = TrustAndSimilarityBasedCF.class.getResourceAsStream("/ml_data_0/u1.test"); 
			BufferedReader testFileReader = null;
			try {
				testFileReader = new BufferedReader(new InputStreamReader(is));
			} catch (Exception e) {
				System.out.println("文件不存在" + e.getMessage());
				return;
			}

			// 创建预测结果写文件
			File outputFile = new File("TSBasedCFResult.txt");
			
			FileWriter writer = null;
			if (!outputFile.exists() && !outputFile.createNewFile()) {
				System.out.println("输出文件创建失败");
			}
			writer = new FileWriter(outputFile);
			String title = "UserID" + "\t" + "ItemID" + "\t" + "OriginalRate" + "\t" + "PredictRate" + "\r\n";
			writer.write(title);
			writer.flush();
			String[] part = new String[3];
			String tmpToRead = "";
			String tmpToWrite = "";
			while ((tmpToRead = testFileReader.readLine()) != null) {
				part = tmpToRead.split("\t");
				int userID = Integer.parseInt(part[0]);
				int itemID = Integer.parseInt(part[1]);
				//获取真实评分
				double originalRate = Double.parseDouble(part[2]);
				//使用本算法中提供的信任-相似性矩阵来进行目标用户针对目标项目的预测评分
				double predictRate = cf.predict(userID, itemID);
				cf.x.add(originalRate);
				cf.y.add(predictRate);
				tmpToWrite = userID + "\t" + itemID + "\t" + originalRate + "\t" + predictRate + "\r\n";
				writer.write(tmpToWrite);
				writer.flush();
			}
			System.out.println("分析完成，请打开工程目录下bin文件夹中的testResult.txt");
			System.out.println("基于信任与近邻评分填充的协同过滤算法的MAE值为:" + cf.produceMAE(cf.x, cf.y));
			System.out.println("基于信任与近邻评分填充的协同过滤算法的RMSE值为:" + cf.calculateRMSE(cf.x, cf.y));
			long endTime = System.currentTimeMillis();
			System.out.println("整个分析推荐过程耗时" + (endTime - startTime)/60000 + "分" + (endTime - startTime) % 60000 + "秒");
			System.out.println();
		} else
			System.out.println("文件读取失败");
	}

	/**以下是基于用户的协同过滤算法的部分方法，本算法中也会用到以下方法，请勿删除**/
	// Chapter1:准备工作
	// 1-1:读取文件内容，得到评分矩阵 1:读取成功 -1：读取失败
	public boolean readFile(String filePath) {
		//URL url = getClass().getClassLoader().getResource(filePath);
		InputStream is = getClass().getResourceAsStream(filePath); 
		
		//File inputFile = new File(url.getFile());
		BufferedReader reader = null;
		try {
			//reader = new BufferedReader(new FileReader(inputFile));
			reader = new BufferedReader(new InputStreamReader(is));
		} catch (Exception e) {
			System.out.println("文件不存在" + e.getMessage());
			return false;
		}

		String sentence = "";
		String[] part = new String[3];
		try {
			while ((sentence = reader.readLine()) != null) {
				part = sentence.split("\t");
				int userID = Integer.parseInt(part[0]);
				int itemID = Integer.parseInt(part[1]);
				double Rate = Double.parseDouble(part[2]);
				// 构造矩阵
				rate[userID][itemID] = Rate;
			}
		} catch (NumberFormatException | IOException e) {
			System.out.println("读文件发生错误" + e.getMessage());
			return false;
		}
		return true;
	}
	
	// hapter1:处理数据稀疏问题
	// 1-1:计算每个用户为几部电影打分
	public void getRateItemNumOfUser() {
		for (int i = 1; i <= USERSIZE; i++) {
			int n = 0;
			for (int j = 1; j <= ITEMSIZE; j++) {
				if (rate[i][j] != 0)
					n++;
			}
			itemNumOfUser[i] = n;
		}
	}

	// 1-2:计算每个用户的平均分
	public void getAverageRateOfUser() {
		int i, j;
		for (i = 1; i <= USERSIZE; i++) {
			double sum = 0.0;
			for (j = 1; j < rate[i].length; j++) {
				sum += rate[i][j];
			}
			averageRateOfUser[i] = sum / itemNumOfUser[i];
		}
	}

	// 计算每个项目有多少人进行了评分
	public void getRateUserNumOfItem() {
		for (int j = 1; j <= ITEMSIZE; j++) {
			int n = 0;
			for (int i = 1; i <= USERSIZE; i++) {
				if (rate[i][j] != 0)
					n++;
			}
			userNumOfItem[j] = n;
		}
	}

	// 计算每个项目的平均评分
	public void getAverageRateOfItem() {
		int i, j;
		for (j = 1; j <= ITEMSIZE; j++) {
			double sum = 0.0;
			for (i = 1; i <= USERSIZE; i++) {
				// 每个length都是ITEMSIZE=1682
				sum += rate[i][j];
			}
			averageRateOfItem[j] = sum / userNumOfItem[j];
		}
	}

	// 1-3:处理评分矩阵的稀疏问题（重要事项！！！）
	// 使用上一步中用户评分的均值填补未评分项
	public void dealRate() {
		int i, j;
		for (i = 1; i <= USERSIZE; i++) {
			for (j = 1; j <= ITEMSIZE; j++) {
				if (rate[i][j] == 0)
					DealedOfRate[i][j] = averageRateOfUser[i];
				else
					DealedOfRate[i][j] = rate[i][j];
			}
		}
	}

	// Chapter2:聚类，找和某一用户有相同喜好的一类用户，即找到用户的K近邻集合
	// 2-1-1:求给定数组的和
	public double Sum(double[] arr) {
		double total = (double) 0.0;
		for (double ele : arr)
			total += ele;
		return total;
	}

	// 2-1-2:计算两个向量的内积，每项乘积求和
	public double Mutipl(double[] arr1, double[] arr2, int len) {
		double total = (double) 0.0;
		for (int i = 0; i < len; i++)
			total += arr1[i] * arr2[i];
		return total;
	}

	// 2-1-3:计算两个向量之间的皮尔逊相似度
	public double Pearson(double[] x, double[] y) {
		int lenx = x.length;
		int leny = y.length;
		int len = lenx;// 小容错
		if (lenx < leny)
			len = lenx;
		else
			len = leny;
		double sumX = Sum(x);
		double sumY = Sum(y);
		double sumXX = Mutipl(x, x, len);
		double sumYY = Mutipl(y, y, len);
		double sumXY = Mutipl(x, y, len);
		double upside = sumXY - sumX * sumY / len;
		// 任何一项为0时，均返回0
		if (equal(sumX, 0.0d) || equal(sumY, 0.0d) || equal(sumXX, 0.0d) || equal(sumYY, 0.0d) || equal(sumXY, 0.0d)) 
			return 0.0d;
		double downside = (double) Math.sqrt((sumXX - Math.pow(sumX, 2) / len) * (sumYY - Math.pow(sumY, 2) / len));
		return upside / downside;
	}

	// 2-2:使用皮尔逊相似度来求用户的近邻集合，即求NeighborOfUser数组
	public void getNeighborOfUser() {
		int neighborID, userID;
		for (userID = 1; userID <= USERSIZE; userID++) {
			// TreeSet会在每次加入元素后，保持元素有序
			Set<Neighbor> neighborList = new TreeSet<Neighbor>();
			Neighbor[] tmpNeighbor = new Neighbor[USERSIZE + 1];
			for (neighborID = 1; neighborID <= USERSIZE; neighborID++) {
				if (neighborID != userID) {
					double sim = Pearson(DealedOfRate[userID], DealedOfRate[neighborID]);
					tmpNeighbor[neighborID] = new Neighbor(neighborID, sim);
					neighborList.add(tmpNeighbor[neighborID]);
				}
			}
			// 从排好序的邻居列表中获取前N个邻居
			int k = 1;
			Iterator<Neighbor> it = neighborList.iterator();
			while (k <= UN && it.hasNext()) {
				Neighbor tmp = (Neighbor) it.next();
				NeighborArray[userID][k] = tmp;
				k++;
			}
		}
	}

	// Chapter3:根据K个邻居对某个项目的评分来计算目标用户的预测评分
	public double predict(int userID, int itemID) {
		// 这里的userID为用户输入，减1后为数组下标
		double sum1 = 0;
		double sum2 = 0;
		for (int i = 1; i <= UN; i++) {
			// 对最近的UN个邻居进行处理
			int neighborID = NeighborArray[userID][i].getID();
			double similarity = NeighborArray[userID][i].getValue();
			sum1 += similarity * (DealedOfRate[neighborID][itemID] - averageRateOfUser[neighborID]);
			sum2 += Math.abs(similarity);
		}
		return averageRateOfUser[userID] + sum1 / sum2;
	}

	// Chapter4:测试
	// u1.test是测试数据集，包含部分用户对部分项目的打分，这些评分在u1.base数据集中未出现
	// 以u1.test的userID，itemID为输入，使用基于用户的相似来计算用户的预测评分，并与u1.test中实际数据比较
	// 部分测试已在main函数中做好，这里实现均方差公式RMSE
	// 它是观测值与真值偏差的平方和 与 观测次数n比值的平方根
	
	// RMSE函数
	public double RMSE(double[] x, double[] y) {
		double rmse = 0;
		int lenx = x.length;
		int leny = y.length;
		int len = lenx;
		// 小容错
		if (lenx < leny)
			len = lenx;
		else
			len = leny;
		double diffSum = 0;
		double diffMutipl;
		for (int i = 0; i < len; i++) {
			diffMutipl = Math.pow((x[i] - y[i]), 2);
			diffSum += diffMutipl;
		}
		rmse = Math.sqrt(diffSum / len);
		return rmse;
	}

	// 计算RMSE，输入两个长度相等的向量
	public double calculateRMSE(List<Double> x, List<Double> y) {
		int lenx = x.size();
		int leny = y.size();
		// 小容错
		int len = lenx;
		if (lenx < leny)
			len = lenx;
		else
			len = leny;
		double[] tmpX = new double[len];
		double[] tmpY = new double[len];
		for (int i = 0; i < len; i++) {
			tmpX[i] = x.get(i);
			tmpY[i] = y.get(i);
		}
		return RMSE(tmpX, tmpY);
	}
	
	public double produceMAE(List<Double> predict, List<Double> real){
		int lenx = predict.size();
		int leny = real.size();
		int len = lenx;
		// 小容错
		if (lenx < leny)
			len = lenx;
		else
			len = leny;
		double diffSum = 0;
		for (int i = 0; i < len; i++) {
			diffSum += Math.abs(predict.get(i)-real.get(i));
		}
		// System.out.println(diffSum + "," + len);
		return diffSum / len;
	}
	
	/***********************基于信任和近邻填充的用户协同过滤推荐算法*********************************/
	/* 公式1*/
	//计算用户相似性矩阵矩阵，使用皮尔逊系数来计算
	public void calculateSimilarityArray() {
		long startTime = System.currentTimeMillis();
		System.out.println("开始计算用户相似度矩阵...");
		for (int u = 1; u <= USERSIZE; u++) {
			for (int v = 1; v<= USERSIZE; v++) {
				if ( u == v) {
					similarityArray[u][v] = 1.0d;
				} else {
					similarityArray[u][v] = Pearson(rate[u], rate[v]);
				}
			}
		}
		long endTime = System.currentTimeMillis();
		System.out.println("耗时" + (endTime - startTime)/1000 + "秒");
		System.out.println();
	}	
	
	/* 公式 2 */
	// 计算用户价值度数组
	public void calculateUserValueArray(double threshold1, double threshold2) {
		if (userValueArray == null) {
			System.out.println("用户价值矩阵为空！");
			return;
		} else if (itemNumOfUser == null) {
			System.out.println("用户项目评价数目数组为空！");
			return;
		} else {
			// 获取用户中最大的评价数量
			int maxItemNum = itemNumOfUser[1];
			for (int i = 2 ; i < itemNumOfUser.length ; i++) {
				if (itemNumOfUser[i] > maxItemNum) {
					maxItemNum = itemNumOfUser[i];
				}
			}
			if (maxItemNum == 0 ) {
				System.out.println("所有用户评价的项目数目为0！");
				return;
			}
			
			for (int i = 1 ; i < userValueArray.length; i++) {
				/**此处如果不加double强制类型转换，userValueArray中的所有值都会变成0**/
				userValueArray[i] = (double)itemNumOfUser[i] / maxItemNum;
			}
			
			// 			// 根据设定的阈值来计算用户价值度数组
			// 			if (threshold1 == 0 || threshold2 == 0 || threshold1 == threshold2) {
			// 				for (int i = 1 ; i < userValueArray.length; i++) {
			// 					userValueArray[i] = itemNumOfUser[i] / maxItemNum;
			// 					
			// 				}
			// 			} else {
			// 				if (threshold1 < threshold2) {
			// 					int tmp = threshold1;
			// 					threshold1 = threshold2;
			// 					threshold2 = tmp;
			// 				}
			// 				// 大于阈值1，价值度为1；介于1-2之间，计算价值度；小于阈值2，价值度为0
			// 				for (int i = 1 ; i < userValueArray.length; i++) {
			// 					if (itemNumOfUser[i] >= threshold1) {
			// 						userValueArray[i] = 1;
			// 					} else if ( itemNumOfUser[i] >= threshold2 && itemNumOfUser[i] < threshold1) {
			// 						userValueArray[i] = itemNumOfUser[i] / maxItemNum;
			// 					} else {
			// 						userValueArray[i] = 0;
			// 					}
			// 				}
			// 			}
		}
	}
	
	/*公式3*/
	// 计算用户评价权威度
	public void calculateUserPowerArray (double threshold) {
		long startTime = System.currentTimeMillis();
		System.out.println("开始计算用户评价权威度...");
		if (rate == null) {
			System.out.println("用户-项目评分矩阵为空！");
			return;
		} else if (S == null) {
			System.out.println("评分阈值项目数组为空！");
			return;
		} else if (userPowerArray == null) {
			System.out.println("用户权威度数组为空！");
			return;
		} else if (itemNumOfUser == null) {
			System.out.println("用户项目评价数目数组为空！");
			return;
		} else if (averageRateOfItem == null) {
			System.out.println("项目平均打分数组为空！");
			return;
		} else if (threshold <= 0.0d || threshold >=1.0d) {
			System.out.println("阈值不合法！");
			return;
		} else {
			// S为用户u评价的项目中，评分偏差小于一定阈值的项目个数
			for (int i = 1; i < USERSIZE + 1 ; i ++) {
				for (int j = 1; j < ITEMSIZE + 1; j++) {
					if (!equal(rate[i][j], 0.0d) && Math.abs(rate[i][j] - averageRateOfItem[j]) / averageRateOfItem[j] <= threshold) {
						S[i] += 1;
					}
				}
			}
			//计算用户权威度数组
			for (int i = 1; i <= USERSIZE ; i ++) {
				userPowerArray[i] = S[i] / itemNumOfUser[i];
			}
		}
		System.out.println("完成用户评价权威度计算...");
		long endTime = System.currentTimeMillis();
		System.out.println("耗时" + (endTime - startTime)/1000 + "秒");
		System.out.println();
	}
	
	// 计算用户综合信任值数组Trust
	public void calculateUserTrust () {
		if (Trust == null) {
			System.out.println("用户信任值数组为空！");
			return;
		} else if (userValueArray == null) {
			System.out.println("用户价值度数组为空！");
			return;
		} else if (userPowerArray == null) {
			System.out.println("用户权威度数组为空！");
			return;
			
		} else {
			double lambda = 0.0d;
			for (int i = 1; i <= USERSIZE ; i ++) {
				lambda = (double) userValueArray[i] / (userValueArray[i] + userPowerArray[i]);
				Trust[i] = (double) (lambda * userValueArray[i] + (1 - lambda) * userPowerArray[i]); 
			}
		}
	}
	
	
	// 计算用户u和v共同评价过的项目集合
	public Set<Integer> getCommonItemSetOfUV(int u, int v) {
		Set<Integer> uRateSet = new HashSet<Integer>();
		Set<Integer> vRateSet = new HashSet<Integer>();
		for (int j = 1; j <= ITEMSIZE; j++) {
			if(!equal(rate[u][j],0.0d) )
				uRateSet.add(new Integer(j));
			if(!equal(rate[v][j], 0.0d)) 
				vRateSet.add(new Integer(j));
		}
		vRateSet.retainAll(uRateSet);
		return vRateSet;
	}

	// 计算D矩阵，用于计算相互信任度
	public void calculateD(double threshold) {
		Set<Integer> commonSet;
		Iterator<Integer> it;
		double TPui = 0.0d;
		int i = 0;
		for(int u = 1; u <= USERSIZE; u++) {
			for(int v = 1; v <= USERSIZE; v++) {
				if (u != v) {
					commonSet = getCommonItemSetOfUV(u,v);
					it = commonSet.iterator();
					TPui = 0.0d;
					i = 0;
					while(it.hasNext()) {
						i = it.next().intValue();
						TPui = (double) (averageRateOfUser[u] + Trust[v] * Math.abs(rate[v][i] - averageRateOfUser[v]));
						if(Math.abs(rate[u][i] - TPui) / rate[u][i] < threshold) {
							D[u][v] += 1;
						}
					}
				} else {
					D[u][v] = 0;
				}
			}
		}
	}
	
	/*公式6*/
	// 计算用户直接信任度
	public void calculateMTrust(double threshold) {
		long startTime = System.currentTimeMillis();
		System.out.println("开始计算用户直接信任度...");
		calculateD(0.5d);
		Set<Integer> commonSet;
		for(int u = 1; u <= USERSIZE; u++) {
			for(int v = 1; v <= USERSIZE; v++) {
				if (u != v) {
					commonSet = getCommonItemSetOfUV(u,v);
					MTrust[u][v] = (double) D[u][v] / commonSet.size();
				} else {
					MTrust[u][v] = 1.0d;
				}
			}
		}
		System.out.println("完成用户直接信任度计算...");
		long endTime = System.currentTimeMillis();
		System.out.println("耗时" + (endTime - startTime)/1000 + "秒");
		System.out.println();
	}
	
	// 获取两个用户的公共邻居
	public Set<Integer> getCommonNeighborOfUV(int u, int v) {
		Set<Integer> commonNeighborSet = new HashSet<Integer>();
		for (int i = 1; i <= USERSIZE; i++) {
			if ( i != u && i !=v) {
				for (int j = 1; j <= ITEMSIZE; j++) {
					if (equal(rate[u][j], 0.0d) && !equal(rate[v][j], 0.0d) &&!equal(rate[i][j], 0.0d))
						commonNeighborSet.add(i);
				}
			}
		}
		return commonNeighborSet;
	}
	
	// 计算所用户之间信任传递人数组
	public void calculateCommonNeighborArray() {
		long startTime = System.currentTimeMillis();
		System.out.println("开始计算用户信任传递人矩阵...");
		StringBuilder sb = new StringBuilder();
		for (int itemId = 1; itemId <= ITEMSIZE; itemId++) {
			for(int u = 1; u <= USERSIZE; u++) {
				for(int v = u + 1; v <= USERSIZE; v++) {
					sb.append(",");
					if ( !equal(rate[u][itemId], 0.0d) && !equal(rate[v][itemId],0.0d)) {
						for (int m = 1; m <= USERSIZE; m++) {
							if ( m != u && m != v && !equal(rate[m][itemId], 0.0d)) {
								sb.append("," + m);
							}
						}
					}
					sb.append(",");
					commonNeighborArray[u][u] = commonNeighborArray[v][u] = sb.toString();
					sb.delete(0, sb.length());
				}
			}
		}
		System.out.println("完成用户信任传递人矩阵计算...");
		long endTime = System.currentTimeMillis();
		System.out.println("耗时" + (endTime - startTime)/1000 + "秒");
		System.out.println();
	}
	
	// 计算所用户之间信任传递人数组
	public void calculateCommonNeighborArray2() {
		long startTime = System.currentTimeMillis();
		System.out.println("开始计算用户信任传递人矩阵...");
		Set<Integer> umSet = null;
		Set<Integer> vmSet = null;
		StringBuilder sb = new StringBuilder();
		for(int u = 1; u <= USERSIZE; u++) {
			for(int v = u + 1; v <= USERSIZE; v++) {
				sb.append(",");
				for (int m = 1; m <= USERSIZE; m++) {
					if ( m != u && m != v) {
						umSet = getCommonItemSetOfUV(u, m);
						vmSet = getCommonItemSetOfUV(v, m);
						if (umSet != null && !umSet.isEmpty() && vmSet != null && !vmSet.isEmpty()) {
							umSet.retainAll(vmSet);
							if (!umSet.isEmpty())
								sb.append("," + m);
						}
					}
				}
				sb.append(",");
				commonNeighborArray[u][u] = commonNeighborArray[v][u] = sb.toString();
				sb.delete(0, sb.length());
			}
		}
		System.out.println("完成用户信任传递人矩阵计算...");
		long endTime = System.currentTimeMillis();
		System.out.println("耗时" + (endTime - startTime)/1000 + "秒");
		System.out.println();
	}	
	
	/*公式7*/
	// 计算用户间接信任度
	public void calculateITrust(double threshold) {
		long startTime = System.currentTimeMillis();
		System.out.println("开始计算用户间接信任度矩阵...");
		if (ITrust == null) {
			System.out.println("间接信任矩阵为空！");
			return;
		} else if (MTrust == null) {
			System.out.println("直接信任矩阵为空！");
			return;
		} else if (commonNeighborArray == null) {
			System.out.println("用户共同邻居矩阵为空！");
			return;
		} else {
			for (int u = 1; u <= USERSIZE; u++) {
				for (int v = 1; v<= USERSIZE; v++) {
					if ( u != v && commonNeighborArray[u][v] != null) {
						String[] commString = commonNeighborArray[u][v].split(",");
						double down = 0.0d;
						double up = 0.0d;
						for (String i : commString) {
							if (!i.equals("")) {
								int m = Integer.valueOf(i);
								if (MTrust[u][m] >= MTrust[m][v])
									up += MTrust[u][m] * MTrust[m][v]; 
								else 
									up += Math.pow(MTrust[u][m], 2);
								down += MTrust[u][m];	
							}
						}
						if (equal(down, 0.0d))
							ITrust[u][v] = 0.0d;
						else
							ITrust[u][v] = up / down;
					} else {
						ITrust[u][v] = 1.0d;
					}
				}
			}
		}
		System.out.println("完成用户间接信任度矩阵计算...");
		long endTime = System.currentTimeMillis();
		System.out.println("耗时" + (endTime - startTime)/1000 + "秒");
		System.out.println();
	}
	
	/*公式8*/
	// 计算综合信任矩阵
	public void calculateZTrustArray() {
		long startTime = System.currentTimeMillis();
		System.out.println("开始计算用户综合信任度矩阵...");
		if (ZTrust == null) {
			System.out.println("综合信任矩阵为空！");
			return;
		} else if (MTrust == null) {
			System.out.println("直接信任矩阵为空！");
			return;
		} else if (ITrust == null) {
			System.out.println("间接信任矩阵为空！");
			return;
		} else {
			double alpha = 0.0d;
			for (int u = 1; u <= USERSIZE; u++) {
				for (int v = 1; v<= USERSIZE; v++) {
					if (u != v) {
						alpha = Math.pow(MTrust[u][v], 2) / (Math.pow(MTrust[u][v], 2) + Math.pow(ITrust[u][v], 2));
						ZTrust[u][v] = alpha * MTrust[u][v] + (1 - alpha) * ITrust[u][v];
					} else {
						ZTrust[u][v] = 1.0d;
					}
				}
			}
		}
		System.out.println("完成用户间综合任度矩阵计算...");
		long endTime = System.currentTimeMillis();
		System.out.println("耗时" + (endTime - startTime)/1000 + "秒");
		System.out.println();
	}
	
	/*公式10*/
	// 计算相似、信任综合矩阵ST
	public void calculateSTrustArray() {
		long startTime = System.currentTimeMillis();
		System.out.println("开始计算信任-相似度矩阵...");
		if (STrust == null) {
			System.out.println("相似信任综合矩阵为空！");
			return;
		} else if (ZTrust == null) {
			System.out.println("综合信任矩阵为空！");
			return;
		} else if (similarityArray == null) {
			System.out.println("相似矩阵为空！");
			return;
		} else {
			for (int u = 1; u <= USERSIZE; u++) {
				for (int v = 1; v<= USERSIZE; v++) {
					if (u != v) {
						if (similarityArray[u][v] > 0.0d && ZTrust[u][v] > 0.0d) {
							STrust[u][v] = 2 * similarityArray[u][v] * ZTrust[u][v] / (similarityArray[u][v] + ZTrust[u][v]);
						} else if (equal(similarityArray[u][v], 0.0d) && ZTrust[u][v] > 0.0d){
							STrust[u][v] = ZTrust[u][v]; 
						} else if (equal(similarityArray[u][v],00d) && equal(ZTrust[u][v], 0.0d)) {
							STrust[u][v] = 0.0d;
						} else {
							STrust[u][v] = 0.0d;
						}
					} else {
						ZTrust[u][v] = 1.0d;
					}
				}
			}
		}
		System.out.println("完成信任-相似度矩阵计算...");
		long endTime = System.currentTimeMillis();
		System.out.println("耗时" + (endTime - startTime)/1000 + "秒");
		System.out.println();
	}
	
	// 根据ST矩阵获取N个最近邻居
	public void calculateNeighborArray() {
		long startTime = System.currentTimeMillis();
		System.out.println("开始计算用户近邻矩阵...");
		int neighborID, userID;
		for (userID = 1; userID <= USERSIZE; userID++) {
			// TreeSet会将加入的Neighbor排好序存放
			Set<Neighbor> neighborList = new TreeSet<Neighbor>();
			Neighbor[] tmpNeighbor = new Neighbor[USERSIZE + 1];
			for (neighborID = 1; neighborID <= USERSIZE; neighborID++) {
				if (neighborID != userID) {
					tmpNeighbor[neighborID] = new Neighbor(neighborID, STrust[userID][neighborID]);
					neighborList.add(tmpNeighbor[neighborID]);
				}
			}
			// 从排好序的邻居列表中获取N最近邻
			int k = 1;
			Iterator<Neighbor> it = neighborList.iterator();
			while (k <= UN && it.hasNext()) {
				Neighbor tmp = (Neighbor) it.next();
				NeighborArray[userID][k] = tmp;
				k++;
			}
		}
		System.out.println("用户近邻矩阵计算已完成...");
		long endTime = System.currentTimeMillis();
		System.out.println("耗时" + (endTime - startTime)/1000 + "秒");
		System.out.println();
	}
	
	boolean equal(double num1, double num2) {
		if ((num1 - num2 > -0.000001) && (num1 - num2) < 0.000001)
			return true;
		else
			return false;
	}
}
